﻿namespace XDesignerDrawer
{
    using System;
    using System.Drawing;

    public class EllipseObject
    {
        private RectangleF myBounds;
        private PointF myCenter;

        public EllipseObject()
        {
            this.myBounds = RectangleF.Empty;
            this.myCenter = PointF.Empty;
        }

        public EllipseObject(Rectangle bounds)
        {
            this.myBounds = RectangleF.Empty;
            this.myCenter = PointF.Empty;
            this.myBounds = new RectangleF((float) bounds.Left, (float) bounds.Top, (float) bounds.Width, (float) bounds.Height);
            this.UpdateSate();
        }

        public EllipseObject(RectangleF bounds)
        {
            this.myBounds = RectangleF.Empty;
            this.myCenter = PointF.Empty;
            this.myBounds = bounds;
            this.UpdateSate();
        }

        public float CompressAngle(float angle)
        {
            if (this.myBounds.Width == this.myBounds.Height)
            {
                return angle;
            }
            double x = this.myBounds.Width * Math.Cos((angle * 3.1415926535897931) / 180.0);
            double y = this.myBounds.Height * Math.Sin((angle * 3.1415926535897931) / 180.0);
            float result = (float) ((Math.Atan2(y, x) * 180.0) / 3.1415926535897931);
            if (result < 0f)
            {
                result += 360f;
            }
            return result;
        }

        public bool Contains(double x, double y)
        {
            double dx = (x - this.myBounds.Left) - (this.myBounds.Width / 2f);
            double dy = (y - this.myBounds.Top) - (this.myBounds.Height / 2f);
            double angle = Math.Atan2(y, x);
            if (angle < 0.0)
            {
                angle += 6.2831853071795862;
            }
            double r = Math.Sqrt((dy * dy) + (dx * dx));
            return (this.GetEllipseRadius(angle) > r);
        }

        public bool Contains(double x, double y, float StartAngle, float SweepAngle)
        {
            double dx = (x - this.myBounds.Left) - (this.myBounds.Width / 2f);
            double dy = (y - this.myBounds.Top) - (this.myBounds.Height / 2f);
            double angle = Math.Atan2(dy, dx);
            if (angle < 0.0)
            {
                angle += 6.2831853071795862;
            }
            double angleDegrees = (angle * 180.0) / 3.1415926535897931;
            float EndAngle = StartAngle + SweepAngle;
            if (((angleDegrees >= StartAngle) && (angleDegrees <= EndAngle)) || ((EndAngle > 360f) && ((angleDegrees + 360.0) <= EndAngle)))
            {
                double r = Math.Sqrt((dy * dy) + (dx * dx));
                return (this.GetEllipseRadius(angleDegrees) > r);
            }
            return false;
        }

        public void Draw(Graphics g, Pen pen, Brush brush)
        {
            if ((g != null) && ((pen != null) || (brush != null)))
            {
                if (brush != null)
                {
                    g.FillEllipse(brush, this.myBounds);
                }
                if (pen != null)
                {
                    g.DrawEllipse(pen, this.myBounds);
                }
            }
        }

        public void Draw(Graphics g, Pen pen, Brush brush, float StartAngle, float SweepAngle)
        {
            if ((g != null) && ((pen != null) || (brush != null)))
            {
                if (brush != null)
                {
                    g.FillPie(brush, this.myBounds.Left, this.myBounds.Top, this.myBounds.Width, this.myBounds.Height, StartAngle, SweepAngle);
                }
                if (pen != null)
                {
                    g.DrawPie(pen, this.myBounds.Left, this.myBounds.Top, this.myBounds.Width, this.myBounds.Height, StartAngle, SweepAngle);
                }
            }
        }

        public double GetEllipseRadius(double angle)
        {
            angle = (angle * 3.1415926535897931) / 180.0;
            double a = this.myBounds.Width / 2f;
            double b = this.myBounds.Height / 2f;
            double a2 = a * a;
            double b2 = b * b;
            double cosFi = Math.Cos(angle);
            double sinFi = Math.Sin(angle);
            return ((a * b) / Math.Sqrt(((b2 * cosFi) * cosFi) + ((a2 * sinFi) * sinFi)));
        }

        public void Offset(float dx, float dy)
        {
            this.myBounds.Offset(dx, dy);
            this.UpdateSate();
        }

        public PointF PeripheraPoint(double angle)
        {
            double rad = (angle * 3.1415926535897931) / 180.0;
            double x = this.myCenter.X + ((this.myBounds.Width * Math.Cos(rad)) / 2.0);
            double y = this.myCenter.Y + ((this.myBounds.Height * Math.Sin(rad)) / 2.0);
            return new PointF((float) x, (float) y);
        }

        public PointF PeripheraPoint2(double angle)
        {
            double rad = (angle * 3.1415926535897931) / 180.0;
            double r = this.GetEllipseRadius(angle);
            double x = this.myCenter.X + (r * Math.Cos(rad));
            double y = this.myCenter.Y + (r * Math.Sin(rad));
            return new PointF((float) x, (float) y);
        }

        public float UnCompressAngle(float angle)
        {
            if (this.myBounds.Width == this.myBounds.Height)
            {
                return angle;
            }
            double x = this.myBounds.Height * Math.Cos((angle * 3.1415926535897931) / 180.0);
            double y = this.myBounds.Height * Math.Sin((angle * 3.1415926535897931) / 180.0);
            float result = (float) ((Math.Atan2(y, x) * 180.0) / 3.1415926535897931);
            if (result < 0f)
            {
                result += 360f;
            }
            return result;
        }

        private void UpdateSate()
        {
            this.myCenter = new PointF(this.myBounds.Left + (this.myBounds.Width / 2f), this.myBounds.Top + (this.myBounds.Height / 2f));
        }

        public RectangleF Bounds
        {
            get
            {
                return this.myBounds;
            }
            set
            {
                this.myBounds = value;
                this.UpdateSate();
            }
        }

        public PointF Center
        {
            get
            {
                return this.myCenter;
            }
        }

        public float Semimajor
        {
            get
            {
                return (float) (((double) this.myBounds.Width) / 2.0);
            }
        }

        public float SemiMinor
        {
            get
            {
                return (float) (((double) this.myBounds.Height) / 2.0);
            }
        }
    }
}

